package com.ld.shieldsb.common.core.encryptor;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

/**
 * PBKDF2不可逆加密工具类<br/>
 * 采用 work factor(也称之为 security factor)或迭代次数作为参数来确定 Hash 函数将变的有多慢，并且随着日后计算能力的提高，可以逐步增大 work factor 来使之与计算能力达到平衡
 * 
 * @ClassName Pbkdf2Encryptor
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2018年12月5日 下午3:13:20
 *
 */
public class Pbkdf2Encryptor {

    public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

    /**
     * 盐的长度
     */
    public static final int SALT_BYTE_SIZE = 32 / 2;

    /**
     * 生成密文的长度
     */
    public static final int HASH_BIT_SIZE = 128 * 4;

    /**
     * 迭代次数
     */
    public static final int PBKDF2_ITERATIONS = 1000;

    /**
     * 对输入的字符进行验证
     * 
     * @param attemptedStr
     *            待验证的字符
     * @param encryptedStr
     *            加密后的字符
     * @param salt
     *            盐值
     * @return 是否验证成功
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static boolean match(String attemptedStr, String encryptedStr, String salt)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 用相同的盐值对用户输入的密码进行加密
        String encryptedAttemptedStr = encrypt(attemptedStr, salt);
        // 把加密后的密文和原密文进行比较，相同则验证成功，否则失败
        return encryptedAttemptedStr.equals(encryptedStr);
    }

    /**
     * 加密
     * 
     * @param input
     *            原字符
     * @param salt
     *            盐值
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static String encrypt(String input, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException {

        KeySpec spec = new PBEKeySpec(input.toCharArray(), ByteUtils.fromHexString(salt), PBKDF2_ITERATIONS, HASH_BIT_SIZE);
        SecretKeyFactory f = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
        return ByteUtils.toHexString(f.generateSecret(spec).getEncoded());
    }

    public static void main(String[] args) {
//        String password = "test";
//        String salt;
//        String ciphertext;
//        try {
//
////            salt = Pbkdf2Encryptor.generateSalt();
//            salt = ByteUtils.toHexString(DigestUtils.getSalt(SALT_BYTE_SIZE));
//            ciphertext = Pbkdf2Encryptor.encrypt(password, salt);
//            boolean result = Pbkdf2Encryptor.match(password, ciphertext, salt);
//
//            System.out.println(password + "  " + password.length());
//            System.out.println(salt + "  " + salt.length());
//            System.out.println(ciphertext + "  " + ciphertext.length());
//            if (result) {
//                System.out.println("succeed");
//            } else {
//                System.out.println("failed");
//            }
//        } catch (NoSuchAlgorithmException e) {
//            System.out.println("NoSuchAlgorithmException");
//        } catch (InvalidKeySpecException e) {
//            System.out.println("InvalidKeySpecException");
//        }
    }
}